package xin.mydreams.purple.bootstrap;

import org.apache.commons.lang3.StringUtils;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.DefaultThreadFactory;
import lombok.extern.slf4j.Slf4j;
import xin.mydreams.purple.config.PurpleSetting;
import xin.mydreams.purple.constant.PurpleConstant;
import xin.mydreams.purple.init.CicadaInitializer;

/**
 * netty 启动
 * 
 * @Type TomcatBootstrap.java
 * @Desc
 * @email guzehao@mydreams.xin
 * @author 谷泽昊
 * @blog https://www.mydreams.xin
 * @date 2018年12月7日 下午8:50:33
 * @version
 */
@Slf4j
public class NettyBootstrap {

	private static EventLoopGroup boss = new NioEventLoopGroup(1, new DefaultThreadFactory("boss"));
	private static EventLoopGroup work = new NioEventLoopGroup(0,
			new DefaultThreadFactory(PurpleConstant.SystemProperties.APPLICATION_THREAD_MAIN_NAME));

	private static Channel channel;

	/**
	 * 启动
	 *
	 * @date Created at 2018年12月7日 下午11:06:08
	 * @emain guzehao@mydreams.xin
	 * @blog https://www.mydreams.xin
	 * @author 谷泽昊
	 * @param start
	 * @throws Exception
	 */
	public static void start(long start) throws Exception {
		// start
		startServer(start);

		// register shutdown hook
		shutDownServer();

		// synchronized channel
		joinServer();
	}

	/**
	 * 启动
	 *
	 * @date Created at 2018年12月7日 下午11:06:20
	 * @emain guzehao@mydreams.xin
	 * @blog https://www.mydreams.xin
	 * @author 谷泽昊
	 * @param start
	 * @throws InterruptedException
	 */
	private static void startServer(long start) throws InterruptedException {
		ServerBootstrap bootstrap = new ServerBootstrap().group(boss, work).channel(NioServerSocketChannel.class)
				.childHandler(new CicadaInitializer());
		String portString = PurpleSetting.getProperty(PurpleConstant.PURPLE_PORT);
		int port = 8080;
		if (StringUtils.isNotBlank(portString)) {
			port = Integer.valueOf(portString);
		}
		String rootPath = PurpleSetting.getProperty(PurpleConstant.PURPLE_CONTEXT_PATH);
		if (StringUtils.isBlank(rootPath)) {
			rootPath = "";
		}
		ChannelFuture future = bootstrap.bind(port).sync();
		if (future.isSuccess()) {
			appLog(start, port, rootPath);
		}
		channel = future.channel();
	}

	/**
	 * 阻挡线程继续，使其保持服务状态
	 *
	 * @date Created at 2018年12月7日 下午11:08:45
	 * @emain guzehao@mydreams.xin
	 * @blog https://www.mydreams.xin
	 * @author 谷泽昊
	 * @throws Exception
	 */
	private static void joinServer() throws Exception {
		channel.closeFuture().sync();
	}

	/**
	 * 成功后的日志
	 *
	 * @date Created at 2018年12月7日 下午11:09:45
	 * @emain guzehao@mydreams.xin
	 * @blog https://www.mydreams.xin
	 * @author 谷泽昊
	 * @param start
	 * @param prot
	 * @param rootPath
	 */
	private static void appLog(long start, int prot, String rootPath) {
		long end = System.currentTimeMillis();
		log.info("Purple started on port: {} {}ms", prot, end - start);
		log.info(">> access http://{}:{}{} <<", "127.0.0.1", prot, rootPath);
	}

	/**
	 * 程序结束后执行
	 */
	private static void shutDownServer() {
		ShutDownThread shutDownThread = new ShutDownThread();
		shutDownThread.setName(PurpleConstant.SystemProperties.APPLICATION_THREAD_SHUTDOWN_NAME);
		Runtime.getRuntime().addShutdownHook(shutDownThread);
	}

	private static class ShutDownThread extends Thread {
		@Override
		public void run() {
			log.info("Cicada server stop...");
//            CicadaContext.removeContext();
//
//            CicadaBeanManager.getInstance().releaseBean();

			boss.shutdownGracefully();
			work.shutdownGracefully();

			log.info("Cicada server has been successfully stopped.");
		}

	}

}
